package org.example;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import java.net.URLEncoder;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

public class RSAUtil {

    public static void main(String[] args) throws Exception {
        RSAKeyPair rsaKeyPair = RSAUtil.generateKeyPair();
//        System.out.println("publicKey:" + rsaKeyPair.getPublicKey());
//        System.out.println("privateKey:" + rsaKeyPair.getPrivateKey());

        String publicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlRhSs3mtTz1WSfZ0h/GgTdvEv4kSnxT+4iCjR4Spijd4FriRJL6/5JaAt1PTTqXaRgqespVXNyOFFjga3GPOKtDZ5HhBVbbBnxX/aTKvuujol6gxzvJE2nXozqObeVfufD1Tw+71wuriwqBhRZBCHqKBj6oMwvS3RgwzSnBKb1MSW56O5iU636BQR+S7hXS2YC7UW/n9Ctb1PDKYdkZ9R3lV8I+F/nPBX1ynIobZsjlfYDDP3odUKgfRSfGTivpMAiMQiS/e71rdBC8HbVnMoV5Z9kCYAL3YkySDxkqys7JTbs4wBL27xiS7+cpHaJHQJgEmEdUmLgvwQBN93QNO/wIDAQAB";
        String privateKey = "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCVGFKzea1PPVZJ9nSH8aBN28S/iRKfFP7iIKNHhKmKN3gWuJEkvr/kloC3U9NOpdpGCp6ylVc3I4UWOBrcY84q0NnkeEFVtsGfFf9pMq+66OiXqDHO8kTadejOo5t5V+58PVPD7vXC6uLCoGFFkEIeooGPqgzC9LdGDDNKcEpvUxJbno7mJTrfoFBH5LuFdLZgLtRb+f0K1vU8Mph2Rn1HeVXwj4X+c8FfXKcihtmyOV9gMM/eh1QqB9FJ8ZOK+kwCIxCJL97vWt0ELwdtWcyhXln2QJgAvdiTJIPGSrKzslNuzjAEvbvGJLv5ykdokdAmASYR1SYuC/BAE33dA07/AgMBAAECggEBAJPDn3MwzIsUB0kWcTeqSW3guYX6m/H+JP6Hyks/N6g8gVBDa9Y3Foe+gaMv+OShi0qPi+kCCYYkNepngHeckt/sTYcZh+cjUZIRgykHixJ7csmbcIHhqku5QBpMG/KPK1UGktZFJl0f3c12lfETn/QsqqtvpWYyktFhlhPYZm0dKO+sfV5t2yT+oafw/mK/1YiT0ZC18fQrdEi5MIqGUya0le3Vv6zpOYn9roLUfcEHNs36YC9ylkrxD6vzGz6V3DdA7M8+7EncJ6ueIXaLwtHTa3F4IrEx8JzzittlgpYRsAv2wde1rJjkMUt0gqOMljfvLfKFmIJbhROlWIVSqgECgYEA36noHljTnSFsCYUIqGoY0gVtyiFg1XDtwtqEXJSW1DQ4NX+5RPMyn0fJNgF56quOzBGulZPvR3kFBaDJDS7M/4Z8Wd6Cm53c4ptXQfRDdkG31wG1WcLV5g1EtDhR8H/XPNTCuCLxvn/uQiQVeRALU7+LA/Gj5Uu4oDNIalxJp6ECgYEAqqaHgG6gX9YhFFE2KkyF07xug9N2XZLr1/c98nZ8PhoxN4MMHmmXcIdLE4sLu7QRLYkm056MzUraZOGusTxLdn5fyMvdPTrR0CCdMsXAAA0kDBBvSlAc2WWqLWUbKraxSR+lcVRh3uJRzf4LBOz56fPbSwPE3poqq+cq0cAO8p8CgYEAlhdDsBG1uA00ndLLc5D3JQEFow3xGGqW8xqGlkYUTUTZr3UNk+qLvv2CVh55fPQxeFopSTEj8leQ+izinlkYsiTCj+BUzy8Jinvp+1V6bAI/5yW7WAf6WE3xG+treTOg8a5pGP5CMa9R6MqkKkCNCV9RX40pifbdZ4vifZV+y+ECgYBDChzdVZhnTeW855KR13ITlkkMPLyZUiiYtSZ+5BE3DG8dUbwnDnBR4rSZvtwjJ0BAVUsNg5Ho7GkTjJ1mPzueF1NlvMDzVvIqA0X+NjWRT5hDrQkrdoF+3jOWlcuwYgkPowEJno68Usi0VgLaMoaTZBtYQujKUmJFGhF2SS8WHQKBgQC32e+DAJemr5oUHCdXlbQ/PTFmnxi/vsUaPLH4x7gT3IxmUNW8uElf8WbU19TWF5jddNOOzIaz3ApRQ/gz1Gu0gTw8RoqF4aUL5QdqDRAk/tz/W+yv+5YEkDLFksNOfdNQEsew1ZNYW3KQU8XVOk0fKg3Jc3Ap4eYg7buowI+VuQ==";

        String encryptMsg = RSAUtil.encryptByPublicKey(publicKey, "abc");

        System.out.println("encryptMsg:" + encryptMsg);

        String encodeUrl = URLEncoder.encode(encryptMsg);
        System.out.println("encodeUrl:" + encodeUrl);

        String decryptMsg = RSAUtil.decryptByPrivateKey(privateKey, encryptMsg);

        System.out.println("解密后的数据为：" + decryptMsg);

    }

    /**
     * 公钥加密
     *
     * @param publicKeyText
     * @param text
     * @return
     */
    public static String encryptByPublicKey(String publicKeyText, String text) throws Exception {
        X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText));
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec2);
        Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithMD5AndMGF1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] result = cipher.doFinal(text.getBytes());
        return Base64.encodeBase64String(result);
    }

    /**
     * 私钥解密
     *
     * @param privateKeyText
     * @param text
     * @return
     * @throws Exception
     */
    public static String decryptByPrivateKey(String privateKeyText, String text) throws Exception {
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText));
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec5);
        Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithMD5AndMGF1Padding");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] result = cipher.doFinal(Base64.decodeBase64(text));
        return new String(result);
    }

    /**
     * 私钥加密
     *
     * @param privateKeyText
     * @param text
     * @return
     * @throws Exception
     */
    public static String encryptByPrivateKey(String privateKeyText, String text) throws Exception {
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText));
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithMD5AndMGF1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
        byte[] result = cipher.doFinal(text.getBytes());
        return Base64.encodeBase64String(result);
    }

    /**
     * 公钥解密
     *
     * @param publicKeyText
     * @param text
     * @return
     * @throws Exception
     */
    public static String decryptByPublicKey(String publicKeyText, String text) throws Exception {
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText));
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
        Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithMD5AndMGF1Padding");
        cipher.init(Cipher.DECRYPT_MODE, publicKey);
        byte[] result = cipher.doFinal(Base64.decodeBase64(text));
        return new String(result);
    }


    /**
     * 私钥签名
     * 算法:SHA256withRSA
     */
    public static String sign(String data, String privateKeyText) throws Exception {
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText));
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey key = keyFactory.generatePrivate(keySpec);
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(key);
        signature.update(data.getBytes());
        return new String(Base64.encodeBase64(signature.sign()));
    }

    /**
     * 公钥验签
     * 算法:SHA256withRSA
     */
    public static boolean verify(String srcData, String sign, String publicKeyText) throws Exception {
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText));
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey key = keyFactory.generatePublic(keySpec);
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initVerify(key);
        signature.update(srcData.getBytes());
        return signature.verify(Base64.decodeBase64(sign.getBytes()));
    }

    /**
     * 构建RSA密钥对
     *
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static RSAKeyPair generateKeyPair() throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(2048);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
        String publicKeyString = Base64.encodeBase64String(rsaPublicKey.getEncoded());
        String privateKeyString = Base64.encodeBase64String(rsaPrivateKey.getEncoded());
        RSAKeyPair rsaKeyPair = new RSAKeyPair(publicKeyString, privateKeyString);
        return rsaKeyPair;
    }


    /**
     * RSA密钥对对象
     */
    public static class RSAKeyPair {

        private String publicKey;
        private String privateKey;

        public RSAKeyPair(String publicKey, String privateKey) {
            this.publicKey = publicKey;
            this.privateKey = privateKey;
        }

        public String getPublicKey() {
            return publicKey;
        }

        public String getPrivateKey() {
            return privateKey;
        }

    }

}
